/*
   Copyright 2011 Matt Conway

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

$(document).ready(function () {
    // populate heading
    $('#title').text(deployment.name);

    // add width, height checking code
    $('#map').width(1000).height(300);

    map = new OpenLayers.Map('map', {
	projection: 'EPSG:900913'
    });

    // OpenStreetMap
    if (deployment.basemap.toLowerCase() == 'osm') {
	var baseLayer = new OpenLayers.Layer.OSM();
    }

    else if (deployment.basemap.toLowerCase() == 'bing') {
	var baseLayer = new OpenLayers.Layer.VirtualEarth();
    }

    else if (deployment.basemap.toLowerCase() == 'yahoo') {
	var baseLayer = new OpenLayers.Layer.Yahoo();
    }

    map.addLayer(baseLayer);
    map.setBaseLayer(baseLayer);

    // populate tool bar
    var html = '';
    styleLookupTable = {};
    var serviceTypesLen = deployment.serviceTypes.length;
    for (var i = 0; i < serviceTypesLen; i++) {
	var st = deployment.serviceTypes[i];
	currentServiceType = st;
	html = jQuery(
	    '<div class="button serviceButton" id="serviceBtn-' + st.id + '"' +
		'stypeseq="' + i + '">' +
		'<a href="#">' +
		'<img src="' + st.icon + '" alt="" width="32"' +
		'height="32"/><br/>' +
		st.name + '</a></div><br/>');
	html.click(setServiceType);
	// for 508 accessibility
	html.find('a').click(function (e) { 
	    e.preventDefault(); 
	    $(this).parent().click();
	});
	
	$('#tools').append(html);

	// add the symbolizer to the lookup table
	styleLookupTable[st.id] = 
	    new OpenLayers.StyleMap(st.symbolizer);
    }

    // set the symbolizer on the vector layer
    //var styleMap = new OpenLayers.StyleMap();
    //styleMap.addUniqueValueRules('default', 'stypeid', styleLookupTable);

    // setup the line and station layers
    // both feature types go on one layer
    vlayer = new OpenLayers.Layer.Vector();

    // when a line or station is added, run this to update the cost
    vlayer.events.register('beforefeatureadded', null, function (e) {
	var feat = e.feature;
	
	// set the type
	feat.attributes.stypeid = currentServiceType.id;
	feat.style = styleLookupTable[currentServiceType.id];

	// dealing with a line
	if  (feat.geometry instanceof OpenLayers.Geometry.LineString) {
	    // here is the default frequency, etc.
	    // span of service
	    feat.attributes.span = 20;
	    // days/week
	    feat.attributes.days = 7;
	    // frequency (mins)
	    feat.attributes.freq = 15;  
	}
	
	displayBudget(calculateBudget());

	// in order to make the styles show
	vlayer.redraw();
    });

    map.addLayer(vlayer);

    drawControls = {
	newLine: new OpenLayers.Control.DrawFeature(vlayer,
						  OpenLayers.Handler.Path),
	newStn : new OpenLayers.Control.DrawFeature(vlayer,
						  OpenLayers.Handler.Point)
    }

    map.addControls([drawControls.newLine, drawControls.newStn]);

    map.setCenter(
	new OpenLayers.LonLat(deployment.initial[1], deployment.initial[0])
	    .transform(
		new OpenLayers.Projection('EPSG:4326'), 
		new OpenLayers.Projection('EPSG:900913')
	    ), // WGS84 to Web Merc
	deployment.initial[2] // zoom
    );

    // activate the function selection buttons
    // todo: need alternate event handler?
    $('#functionSelector form input[name="fn"]').click(function (e) {
	for (var c in drawControls) drawControls[c].deactivate();
	//navigation: no controls active.
	if (e.target.value != 'navigate')
	    drawControls[e.target.value].activate();
    });

    // select navigate to start
    $('#functionSelector form input[value="navigate"]').click();
});

function setServiceType (e) {
    e.preventDefault();

    // deselect all of the other service types
    $('.serviceButton')
	.removeClass('serviceButtonSelected')
	.attr('title', '');

    var button = $(this);
    button.addClass('serviceButtonSelected').attr('title', 'selected');

    currentServiceType = deployment.serviceTypes[Number(button.attr('stypeseq'))];
    var st = currentServiceType;

    if (st.stations == false) 
	$('#functionSelector form .station').fadeOut();
    else $('#functionSelector form .station').fadeIn(); 

    // slide the controls down
    $('#functionSelector').slideDown();
}

// given an ID, retrieve the service type by that ID
function getServiceTypeById (id) {
    id;
    var stLen = deployment.serviceTypes.length;
    for (var i = 0; i < stLen; i++)
	// by casting the id to text, they can use a number (e.g. 2) or
	// a word (e.g. UBART) to specify a service type
	if (String(deployment.serviceTypes[i].id) == id)
	    return deployment.serviceTypes[i];
    // if we get this far, no such type
    return null;
}

// convert map units (meters) to deployment units
function convertLength (l) {
    if (deployment.units == 'km') return l/1000;
    if (deployment.units == 'mi') return l/1609;
}

// calculate how much this all costs
function calculateBudget() {
    // loop over each feature in vlayer
    var costByMode = {};
    
    var vlFlen = vlayer.features.length;
    for (i = 0; i < vlFlen; i++) {
	feat = vlayer.features[i];
	var st = getServiceTypeById(feat.attributes.stypeid);
	// ignore feature with no service type
	// TODO: best behavior? Simulated dialog asking to choose svc type
	// would be better.
	if (st == null) break;
	
	if (costByMode[st.id] == undefined) costByMode[st.id] = {};

	if (feat.geometry instanceof OpenLayers.Geometry.Point) {
	    // station
	    if (costByMode[st.id].capitalCost == undefined)
		costByMode[st.id].capitalCost = st.stationCost;
	    else costByMode[st.id].capitalCost += st.stationCost;
	}

	else {
	    var len = convertLength(feat.geometry.getLength());
	    if (costByMode[st.id].capitalCost == undefined)
		costByMode[st.id].capitalCost = st.capitalCost * len;
	    else costByMode[st.id].capitalCost += st.capitalCost * len;

	    var opCost = ((st.opCost * len * feat.attributes.span * feat.attributes.days)/feat.attributes.freq);
	    if (costByMode[st.id].opCost == undefined)
		costByMode[st.id].opCost = opCost;
	    else costByMode[st.id].opCost += opCost;
	    
	}
    }

    return costByMode;
}

function makePrettyNumber(n) {
    if (n >= 1000000000) return (Math.round(n/10000000)/100)+'T';
    if (n >= 1000000) return (Math.round(n/10000)/100)+'M';
    if (n >= 1000) return (Math.round(n/10)/100)+'K';
}

// display the cost in a table
function displayBudget(costByMode) {
    var html = '<h3 class="accessiblehidden">cost</h3><table>' +
	'<tr><th scope="col">service</th><th>capital cost</th>' +
	'<th scope="col">operating cost</th></tr>';
    var totals = {};
    totals.operating = 0;
    totals.capital = 0;
    for (var i in costByMode) {
	var mode = costByMode[i];
	if (mode.opCost == undefined) {
	    totals.capital += mode.stationCost;
	}
	else {
	    totals.capital += mode.capitalCost;
	    totals.operating += mode.opCost;
	}

	html += '<tr><th scope="row">' + getServiceTypeById(i).name + '</th>' +
	    '<td>' + makePrettyNumber(mode.capitalCost) + '</td>' +
	    '<td>' + makePrettyNumber(mode.opCost) + '/yr</td></tr>';
    } 

    html += '<tr class="total"><th scope="row">Totals</th>' +
	'<td>' + makePrettyNumber(totals.capital) + '</td>' +
	'<td>' + makePrettyNumber(totals.operating) + '/yr</td></tr>'; 

    html += '</table>';
    $('#cost').html(html);
}
		 

// When we search for a location, do it
function nominatim(e) {
    e.preventDefault();

    // Clear it out
    $('.nominatim_result').remove();
    $('.nominatim_err').remove();

    $.ajax({
	url: 'http://nominatim.openstreetmap.org/search',
	data: {format: 'json', q: $('#nominatim_input').val()},
	dataType: 'json',
	success: function (data) {
	    if (data.length == 0) {
		$('#nominatim_results').append('<div class="nominatim_err">No results found for query ' + $('#nominatim_input').val() + '</div>');
		$('#nominatim_results').slideDown();
	    }

	    else if (data.length == 1) {
		$('#nominatim_results').slideUp(); // In case it isn't
		// (repeated searches)
		centerMap(data[0].lon, data[0].lat);
	    }

	    else {
		data.forEach(function (place) {
		    thediv  = '<div class="nominatim_result">';
		    thediv += '<a href="#" onclick="centerMap(' + place.lon + ',' + place.lat + ')">';
		    thediv += place.display_name + '</a>';
		    $('#nominatim_results').append(thediv);
		});
		$('#nominatim_results').slideDown();
	    }
	}
    });
}

// Center the map
function centerMap(lon, lat) {
    // Hide the results
    $('#nominatim_results').slideUp();
    $('#nominatim_result').remove();
    map.setCenter(lonlat(lon, lat), 15)
}
